import React from 'react';
import { Button, Icon, Input, message } from 'antd';
import { WeaLocaleProvider } from 'ecCom';
import { getFileIcon, nameRule_compatible, strByteLen, strByteSlice } from '../../../util';
import '../../style/fileItem.less';

const getLabel = WeaLocaleProvider.getLabel;

/*
* props属性：
* type            文件还是文件夹？file folder【必需】
* textname        文件名称【必需】
*
* collectable     是否启用收藏
* isFav           是否已收藏
* onClick         整个组件的点击事件（参数：key, e）
* onDoubleClick   整个组件的双击事件（参数：key, e）
* onFav           点击收藏图标的事件（参数：key）
*
* editable        是否可编辑文件名
* editing         初始化编辑状态
* editStart       点击编辑按钮的回调（返回值：false可阻止编辑，true允许编辑）
* onChange        文本编辑框input的onchange事件（参数：key, val。返回值：string）
* onOk            确认编辑的点击事件（参数: key, val）
* onCancel        取消编辑的点击事件（参数: key）
*
*
* selectable      是否开启选择
* selectKey       每个文件/文件夹的唯一标识，一般是id
* selected        是否被选中
* rightSelect     是否允许右键选择
*
*
* */

/*
* 说明：
*  1.关于编辑文件名时，不允许同时编辑多个的需求。
*     本组件不提供此功能。你可以通过业务代码来控制。思路：
*     两种方法都最好借助store中的"editing"变量来判断当前是否有正在编辑的项，建议第二种
*        (1)通过editable属性，当editing为true时，所有组件的editable都为false。这其实会触发所有组件的渲染，不建议。
*        (2)通过editStart回调，当editing为true时，editStart回调返回false，即可阻止编辑。
*     当然还需要配合onCancel和onOk
*  2.关于选中。
*     本组件只针对单个个体提供选择功能，但无法从全局提供单选（排斥选择）。解决方法：
*     利用受控属性selected，实现选中的逻辑，操作每个组件的selected即可。
*     建议：在store中维护一个"selectedKeys"的数组/对象，逻辑通过操作selectedKeys实现，通过autorun监控selectedKeys的变化，
*        进而改变原始数据，实现页面的更新。
*  3.关于收藏功能
*     收藏和取消收藏，需要后端接口的反馈才能确定是否操作成功，因此只提供了onFav回调。需要在业务代码中改变对应的isFav属性值即可。
*
* */


class WeaDocFileItem extends React.Component {
   static defaultProps = {
      type: 'file',
      collectable: false,
      isFav: false,
      onFav: null,
      onClick: null,
      editable: false,
      editing: false,
      editStart: null,
      selectable: false,
      rightSelect: false,
      titleType: 'none',
      titleText: undefined,
      titlePosition: { icon: { x: 10, y: 17 }, name: { x: 7, y: 12 } },
      ctrlX: false,
   };

   constructor(props) {
      super(props);
      const { type, textname, iconType, titleText, titleType } = this.props;
      this.state = {
         currentIcon: getFileIcon(type, textname, 'picture', iconType), // 判断文件类型并返回图标路径
         editing: this.props.editing,
         site: { x: -1, y: -1, type: '' },
      };
      this.tip = {
         icon: { time: 0, timer: null },
         name: { time: 0, timer: null },
      };
      this.mouse = { x: -1, y: -1 };
      this.iconAttribute = {
         onMouseEnter: this.imgTipEnter,
         onMouseLeave: this.imgTipLeave,
         title: titleText && titleType === 'default' ? (titleText.icon ? titleText.icon : '') : '',
      };
      this.dragParam = { enterChild: false };
   }

   // 监听鼠标位置
   monitorMouseMove = (e) => {
      e.stopPropagation();
      this.mouse = { x: e.pageX, y: e.pageY };
   };
   // 监听鼠标离开
   monitorMouseLeave = () => {
 this.mouse = { x: -1, y: -1 }; 
};

   // 点击编辑图标的事件
   clickEditIcon = (e) => {
      e.stopPropagation();
      const { editStart, selectKey, editMode, selectMode } = this.props;
      let isEdited;
      if (editMode === 1 && selectMode === 1 && e.ctrlKey) // todo 出现更多选中模式时，考虑是否将其纳入误操作的范畴
      {
         return; // 多选时避免误操作
      }
      typeof editStart === 'function' && (isEdited = editStart(selectKey));
      isEdited = isEdited === false ? isEdited : true;
      this.setState({ editing: isEdited });
   };

   // 编辑取消的钩子 onCancel
   editCancel = () => {
      const { onCancel, selectKey } = this.props;
      typeof onCancel === 'function' && onCancel(selectKey);
      this.setState({ editing: false });
   };

   // 确认编辑的钩子 onOk
   editSubmit = (val) => {
      const { onOk, selectKey } = this.props;
      let isSubmit,
editing;
      typeof onOk === 'function' && (isSubmit = onOk(selectKey, val));
      isSubmit = isSubmit === false ? isSubmit : true;
      editing = !isSubmit;
      this.setState({ editing });
   };

   // 编辑onChange事件
   editChange = (val) => {
      const { onChange, selectKey } = this.props;
      let userControl;
      typeof onChange === 'function' && (userControl = onChange(selectKey, val));
      return userControl;
   };

   // 组件被点击onClick
   clickItemHandle = (e) => {
      const { onClick, selectable, selectKey, onSelect } = this.props;
      typeof onClick === 'function' && onClick(selectKey, e); // 将当前点击的key及事件对象
      selectable && typeof onSelect === 'function' && onSelect(selectKey, e); // 选中事件
   };

   // 组件被右击onContextMenu
   rightClickItem = (e) => {
      e.preventDefault();
      const { rightSelect, selectable, selectKey, onSelect } = this.props;
      selectable && rightSelect && typeof onSelect === 'function' && onSelect(selectKey, e); // 选中事件
   };

   // 组件被双击
   DoubleClickItemHandle = (e) => {
      const { onDoubleClick, selectKey } = this.props;
      typeof onDoubleClick === 'function' && onDoubleClick(selectKey, e);
   };

   // 处理收藏功能
   collectHandle = (e) => {
      e.stopPropagation();
      const { onFav, selectKey } = this.props;
      typeof onFav === 'function' && onFav(selectKey);
   };

   // 阻止双击事件冒泡
   banDbClick = (e) => {
      e.stopPropagation();
   };

   // mouseEnter记录初始时间
   imgTipEnter = (e) => {
 this.TipEnterHandle('icon', e); 
};
   nameTipEnter = (e) => {
 this.TipEnterHandle('name', e); 
};
   TipEnterHandle = (type) => {
      const { titleType, titleText } = this.props;
      if (titleType === 'toolTip' && titleText && titleText[type]) {
         this.tip[type].time = new Date().getTime();
         this.tip[type].timer = setTimeout(() => {
            const { titlePosition: p } = this.props;
            this.setState({ site: { x: this.mouse.x + p[type].x, y: this.mouse.y + p[type].y, type } });
         }, 450);
      }
   };
   // mouseleave
   imgTipLeave = (e) => {
 this.TipLeaveHandle('icon', e); 
};
   nameTipLeave = (e) => {
 this.TipLeaveHandle('name', e); 
};
   TipLeaveHandle = (type, e) => {
      this.tip[type].timer && clearTimeout(this.tip[type].timer);
      this.tip[type].timer = null;
      e.relatedTarget.className !== 'WeaDoc-FileItemTitle' && this.setState({ site: { x: -1, y: -1, type: '' } });
   };
   // 传给title组件的方法, 功能：title消失
   cancelTip = (param = {}) => {
 this.setState({ site: param }); 
};

   // dragStart事件
   dragStartHandle = (e) => {
      // e.persist();
      const { selectable, onSelect, selectKey, getSelectKeys, textname, downloadUrl, browser: b, setItemData } = this.props;
      const keys = getSelectKeys();
      const single = !Object.prototype.hasOwnProperty.call(keys, selectKey);
      selectable && single && typeof onSelect === 'function' && onSelect(selectKey, e); // 仅 当前没选中自己 触发onSelect回调
      const dragKeys = single ? [selectKey] : Object.keys(keys);
      const attribute = b.browser === 'edge' || (b.browser === 'ie' && b.version >= 11) ? 'Text' : 'keys'; // 兼容Edge

      if (b.browser === 'ie') // 兼容国产IE内核
      {
         b.version >= 11 && setItemData({ drag: dragKeys });
      } else {
         e.dataTransfer.setData(`${attribute}`, JSON.stringify(dragKeys));
      }

      // 拖动下载 仅Chromium有效 https://qd.myapp.com/myapp/qqteam/pcqq/PCQQ2019.exe todo 下载URL
      attribute === 'keys' && e.dataTransfer.setData('DownloadURL', 'application/octet-stream:Da<jia.exe:https://qd.myapp.com/myapp/qqteam/pcqq/PCQQ2019.exe');
      downloadUrl && attribute === 'keys' && e.dataTransfer.setData('DownloadURL', `application/octet-stream:${textname}:${downloadUrl}`);

      if (Object.keys(keys).length > 0) {
         // e.dataTransfer.addElement(getSelectDOM()[0]);
         // let img = new Image(); img.src = "/spa/document/images/netdisk/picture/drag2.png";
         // e.dataTransfer.setDragImage(img, 47, 45);
      }
   };

   // dragEnd事件
   dragEndHandle = () => {
      const { browser: b, setItemData } = this.props;
      b.browser === 'ie' && b.version >= 11 && setItemData({ drag: [] });
   };

   // dragEnter事件：被拖动元素进入容器上方的容器事
   dragEnterHandle = (e) => {
      if (e.target === this.ItemDOM) { // classList.includes("WeaDoc-FileViewItem")
         !e.target.className.includes('WeaDoc-FileItemSelected') && (e.target.className += ' WeaDoc-FileItemSelected');
      } else {
         this.dragParam.enterChild = true;
      }
   };
   // dragOver事件：被拖动元素在容器上方移动的容器事件
   dragOverHandle = (e) => {
 e.preventDefault(); 
};
   // dragLeave事件：被拖动元素离开容器的容器事件
   dragLeaveHandle = (e) => {
      if (e.target === this.ItemDOM) {
         if (!this.dragParam.enterChild) {
            let className = e.target.className;
            className.includes('WeaDoc-FileItemSelected') && (e.target.className = className.replace(' WeaDoc-FileItemSelected', ''));
         } else {
            this.dragParam.enterChild = false;
         }
      } else {
         this.dragParam.enterChild = false;
      }
   };
   // drop事件 - 元素被释放时的容器事件
   dropHandle = (e) => {
      e.persist();
      e.preventDefault();
      const { draggable, dragSuccess, selectKey, browser: b, getItemData, setItemData } = this.props;
      let keys;
      if (b.browser === 'ie' && b.version >= 11) // 兼容国产IE内核
      {
         keys = getItemData().drag;
         setItemData({ drag: [] });
      } else {
         const attribute = b.browser === 'edge' ? 'Text' : 'keys'; // 兼容Edge
         keys = JSON.parse(e.dataTransfer.getData(`${attribute}`));
      }
      let flag = false,
target = e.target,
className = e.target.className;
      while (!flag && target.tagName !== 'BODY') {
         className = target.className ? target.className : '';
         className && className.includes('WeaDoc-FileViewItem') && (flag = true);
         if (flag) {
            break;
         } else {
            target = target.parentNode ? target.parentNode : '';
         }
      }
      target.className.includes('WeaDoc-FileItemSelected') && (target.className = className.replace(' WeaDoc-FileItemSelected', ''));
      draggable && !keys.includes(selectKey) && typeof dragSuccess === 'function' && dragSuccess(selectKey, keys); // 传参 to, keys
   };

   // 截取字符串
   sliceText = (textname) => {
      const { textCharLen, textByteLen } = this.props;
      if (typeof textCharLen === 'number') {
         return textname.length <= textCharLen ? textname : `${textname.substring(0, textCharLen)}...`;
      } else if (typeof textByteLen === 'number') {
         return strByteLen(textname) <= textByteLen ? textname : `${strByteSlice(textname, textByteLen)}...`;
      }
      return textname;
   };


   render() {
      const { currentIcon, editing } = this.state;
      const { font, iconType, collectable, isFav, selectable, selected, textname, editable, type, ctrlX, titleType, titleText,
         draggable: drag, namingRules, editMode, itemClass, itemStyle } = this.props;

      const dragCon = type === 'folder';
      const showText = font.isExtra && !font.isObserver ? this.sliceText(textname) : textname;

      return (
         <div className={`WeaDoc-FileViewItem${selectable && selected ? ' WeaDoc-FileItemSelected' : ''}${ctrlX ? ' ctrlX' : ''}${itemClass ? ` ${itemClass}` : ''}`}
           onClick={this.clickItemHandle}
           onDoubleClick={this.DoubleClickItemHandle}
           onContextMenu={this.rightClickItem}
           ref={(e) => {
 this.ItemDOM = e; 
}}
           onMouseMove={this.monitorMouseMove}
           onMouseLeave={this.monitorMouseLeave}
           style={itemStyle || {}}
           draggable={drag}
           onDragStart={drag && this.dragStartHandle}
           onDragEnd={drag && this.dragEndHandle}
           onDragEnter={drag && dragCon && this.dragEnterHandle}
           onDragLeave={drag && dragCon && this.dragLeaveHandle}
           onDragOver={drag && dragCon && this.dragOverHandle}
           onDrop={drag && dragCon && this.dropHandle}
         >
            {
               collectable ?
                  <div className={isFav ? 'icon-coms-Collection2' : 'icon-coms-Collection'} onClick={this.collectHandle} onDoubleClick={this.banDbClick} />
                  : null
            }
            <div className="WeaDoc-Main">
               {
                  iconType === 'svg'
                     ?
                        type === 'folder'
                        ?
                        <img src={currentIcon} alt={textname} className="fileIcon" draggable={false} {...this.iconAttribute} />
                        :
                        <i className={`${currentIcon.icon} fileIcon`} style={{ color: currentIcon.color }} {...this.iconAttribute} />
                     :
                  iconType === 'img'
                     ?
                     <img src={currentIcon} alt={textname} className="fileIcon" draggable={false} {...this.iconAttribute} />
                     :
                     null
               }
               {/* <div className="WeaDoc-Key">{ selectKey }</div> */}
               <div className={`WeaDoc-showName${font.fClass ? ` ${font.fClass}` : ''}`}>
                  <div className={'textname'}
                    onMouseEnter={this.nameTipEnter}
                    onMouseLeave={this.nameTipLeave}
                    onClick={editMode === 1 && this.clickEditIcon}
                    onDoubleClick={editMode === 1 && this.banDbClick}
                    title={titleText && titleType === 'default' ? (titleText.name ? titleText.name : '') : ''}
                  >
                     { showText }
                  </div>
                  { editable && !editing && editMode === 0 ? <i className="Edit-Icon icon-coms-edit" onClick={this.clickEditIcon} onDoubleClick={this.banDbClick} /> : null }
               </div>
               { titleText && titleType === 'toolTip' ? <Title ecId={`${this && this.props && this.props.ecId || ''}_Title@lzz7wh`} text={titleText} site={this.state.site} drag={drag} method={this.cancelTip} /> : null }
            </div>
            {
               editing ?
                  <EditName ecId={`${this && this.props && this.props.ecId || ''}_EditName@ul2tx7`} value={textname} type={type} onChange={this.editChange} onOk={this.editSubmit} onCancel={this.editCancel} editMode={editMode} namingRules={namingRules} />
                  : null
            }
         </div>
      );
   }
}


// 编辑框组件
class EditName extends React.Component {
   constructor(props) {
      super(props);
      let [name, ext] = this.judge(); // 受控数据初始值
      const [flag, fullName, Name] = this.namingSchemeHandle(this.props.value, name, 'turn'); // 检查文件名是否符合规范，若否，将不合规的字符转化成下划线
      this.state = {
         inputValue: flag ? name : Name,
         fullName: flag ? this.props.value : fullName,
         start: -1,
         end: -1,
         error: '',
      };
      this.ext = ext;
      this.initialValue = name;
   }

   componentDidMount() {
      // const inputDom = this.inputRef.refs.inputNormal.refs.input.refs.input;
      const inputDom = this.inputRef.refs.input;
      inputDom.focus(); // 组件挂载时聚焦
      // todo 多语言
      this.state.inputValue === getLabel(513708, '新建目录') && inputDom.select(); // 如果是新建文件夹则选中文本
      inputDom.addEventListener('keydown', this.enterDown);
   }

   componentWillUnmount() {
      // const inputDom = this.inputRef.refs.inputNormal.refs.input.refs.input;
      const inputDom = this.inputRef.refs.input;
      inputDom.removeEventListener('keydown', this.enterDown);
   }

   componentDidUpdate(prevProps, prevState) {
      if (this.state.inputValue === prevState.inputValue) { // 光标矫正
         const inputDom = this.inputRef.refs.input;
         inputDom.setSelectionRange(this.state.start, this.state.end);
      }
   }

   // enter键提交
   enterDown = (e) => {
      e.stopPropagation();
      const { editMode } = this.props;
      if (e.keyCode === 13 && e.key.toLowerCase() === 'enter') {
         editMode === 0 && this.submitHandle();
         editMode === 1 && this.inputRef.refs.input.blur(); // blur事件
      }
   };

   // 生成初始受控数据
   judge = () => {
      const { type } = this.props;
      let fullName = this.props.value;
      let name = '',
ext = '';
      if (type === 'file') {
         name = fullName.split('.');
         ext = name.pop();
         name = name.join('.');
      } else if (type === 'folder') {
         name = fullName;
      }
      return [name, ext];
   };

   // input框onchange事件回调
   handleChange = (e) => {
      const { onChange, namingRules, type } = this.props;
      let name = e.target.value,
fullName = `${name}${type === 'file' ? `.${this.ext}` : ''}`,
ext = this.ext;
      let userControl,
flag = true;

      namingRules === 'compatible' && ([flag, fullName, name] = this.namingSchemeHandle(fullName, name)); // 命名规则处理
      flag && typeof onChange === 'function' && (userControl = onChange({ fullName, name, ext })); // 回调

      let stateData = {
         inputValue: flag ? name : this.state.inputValue,
         fullName: flag ? fullName : `${this.state.inputValue}${type === 'file' ? `.${ext}` : ''}`,
         start: e.target.selectionStart - 1,
         end: e.target.selectionEnd - 1,
      };
      userControl === undefined && this.setState(stateData);
      typeof userControl === 'string' && this.setState({
         inputValue: userControl, fullName: `${userControl}${type === 'file' ? `.${ext}` : ''}`, start: e.target.selectionStart - 1, end: e.target.selectionEnd - 1,
      });
   };

   // 阻止双击事件冒泡排序
   stopPropagate = (e) => {
 e.stopPropagation(); 
};

   // 点击按钮
   clickOpera = (e, isSubmit) => {
      e.stopPropagation();
      switch (isSubmit) {
         case true:
            this.submitHandle();
            break;
         case false:
            this.cancelHandle();
            break;
         case undefined:
            this.state.inputValue === this.initialValue ? this.cancelHandle() : this.submitHandle();
            break;
         default:
            this.state.inputValue === this.initialValue ? this.cancelHandle() : this.submitHandle();
            break;
      }
   };

   // 提交事件，触发onOK
   submitHandle = () => {
      const { onOk, namingRules } = this.props;
      let flag = true,
fullName = this.state.fullName,
name = this.state.inputValue.trimLeft(),
ext = this.ext;

      namingRules === 'compatible' && ([flag, fullName, name] = this.namingSchemeHandle(fullName, name)); // 命名规则处理

      flag && name && typeof onOk === 'function' && onOk({ fullName, name, ext });
      flag && !name && message.warn(getLabel(125692, '名称不能为空'));
   };

   // 取消编辑事件，触发onCancel
   cancelHandle = () => {
      const { onCancel } = this.props;
      typeof onCancel === 'function' && onCancel();
      this.setState({
         inputValue: this.initialValue,
         fullName: `${this.initialValue}${this.props.type === 'file' ? `.${this.ext}` : ''}`,
      });
   };

   // 命名规则处理
   namingSchemeHandle = (fullName, name, turn) => {
      // turn === "turn"表示，不合规的字符会被修改成下划线
      const { namingRules } = this.props;
      namingRules !== 'none' && (fullName = fullName.trim()) && (name = name.trimLeft()); // 去除空格(扩展名前的空格不去除)
      let flag = true;

      switch (namingRules) {
         case 'compatible':
            [flag, fullName, name] = nameRule_compatible(fullName, name, turn);
            break;
         default:
            break;
      }

      return [flag, fullName, name];
   };

   render() {
      const { inputValue } = this.state;
      const { editMode } = this.props;

      return (
         <div className="EditName" onDoubleClick={this.stopPropagate} onClick={this.stopPropagate}>
            <Input ecId={`${this && this.props && this.props.ecId || ''}_Input@1l0uhh`} size="large"
              type="text"
              value={inputValue}
              ref={(e) => {
 this.inputRef = e; 
}}
              onBlur={editMode === 1 && this.clickOpera}
              placeholder={getLabel(125692, '名称不能为空')}
              onChange={this.handleChange}
            />
            {
               editMode === 0
                  ?
                  <div className="buttonGroup">
                     <Button ecId={`${this && this.props && this.props.ecId || ''}_Button@p1fky8`} type="ghost" className="opera-left" onClick={(e) => {
 this.clickOpera(e, true); 
}}><Icon ecId={`${this && this.props && this.props.ecId || ''}_Icon@xi47gj`} type="check" /></Button>
                     <Button ecId={`${this && this.props && this.props.ecId || ''}_Button@nsk8x9`} type="ghost" className="opera-right" onClick={(e) => {
 this.clickOpera(e, false); 
}} disabled={inputValue.length === 0}><Icon ecId={`${this && this.props && this.props.ecId || ''}_Icon@6k2uqx`} type="cross" /></Button>
                  </div>
                  :
                  null
            }
         </div>
      );
   }
}


// 替代原生title效果的组件
class Title extends React.Component {
   // 生成最新的内联样式
   getStyle = () => {
      const { site } = this.props;
      let IconStyle = {},
NameStyle = {};
      if (site.type === 'icon') {
         if (site.x !== -1 && site.y !== -1) {
            IconStyle = { display: 'block', left: site.x, top: site.y, animation: 'TitleShow 90ms ease 0s' };
         }
      } else if (site.type === 'name') {
         if (site.x !== -1 && site.y !== -1) {
            NameStyle = { display: 'block', left: site.x, top: site.y, animation: 'TitleShow 90ms ease 0s' };
         }
      }

      return { IconStyle, NameStyle };
   };

   // 鼠标进入
   mouseEnter = (e) => {
      e.target.parentNode.parentNode.setAttribute('draggable', false); // 禁止Item拖拽
   };

   // 鼠标离开title则消失
   mouseLeave = (e) => {
      const { method, drag } = this.props;
      drag && e.target.parentNode.parentNode.setAttribute('draggable', true); // 恢复Item拖拽
      method({ x: -1, y: -1, type: '' });
   };

   // 阻止冒泡
   stopBubble = (e) => {
 e.stopPropagation(); 
};

   // 阻止默认事件
   stopDefault = (e) => {
 e.preventDefault(); 
};

   render() {
      const { text } = this.props;
      const { IconStyle, NameStyle } = this.getStyle();

      return (
         typeof text === 'object' ?
            <React.Fragment ecId={`${this && this.props && this.props.ecId || ''}_undefined@08e0jj`}>
               <div className="WeaDoc-FileItemTitle"
                 style={IconStyle}
                 onClick={this.stopBubble}
                 onMouseEnter={this.mouseEnter}
                 dangerouslySetInnerHTML={{ __html: text.icon ? text.icon : '' }}
                 onMouseLeave={this.mouseLeave}
               />
               <div className="WeaDoc-FileItemTitle"
                 style={NameStyle}
                 onClick={this.stopBubble}
                 onMouseEnter={this.mouseEnter}
                 dangerouslySetInnerHTML={{ __html: text.name ? text.name : '' }}
                 onMouseLeave={this.mouseLeave}
               />
            </React.Fragment>
         : null
      );
   }
}


export default WeaDocFileItem;
